#ifndef __XDGVLC_H__
#define __XDGVLC_H__

#include <QObject>
#include <QTime>
#include <QTimer>
#include <atomic>
#include <vlc/vlc.h> // 引入VLC核心头文件

// 前置声明 QWidget，可以避免在头文件中引入整个 <QWidget>，加快编译速度
class QWidget;


/**
 * @brief 描述播放器的当前状态。
 */
enum class PlayerState {
    NothingSpecial = 0, // 初始状态，无特殊状态
    Opening,        // 正在打开媒体（例如，连接网络流、读取文件头）
    Buffering,      // 正在缓冲数据（常见于网络流，为流畅播放准备数据）
    Playing,        // 正在播放
    Paused,         // 已暂停
    Stopped,        // 已停止（由用户操作，通常位置会归零）
    Ended,          // 已播放到结尾
    Error           // 发生错误，无法播放
};


/**
 * @struct MediaInfo
 * @brief 存放媒体元数据信息的结构体，作为一个纯粹的数据容器。
 */
struct MediaInfo {
    qint64  duration;    // 时长 (单位：毫秒)
    QString  durationText;    // 时长 (文本：时分秒)
    QString title;       // 媒体标题
    QString copyright;   // 版权信息
    QString description; // 描述或备注
    QString date;        // 发布日期
    QString url;         // 来源网址
    QString language;    // 语言
    QString encodedBy;   // 编码者
};

/**
 * @class xdgVLC
 * @brief 一个高内聚、低耦合的VLC播放器核心类。
 *
 * 这个类封装了 libvlc 的核心功能，包括媒体加载、播放控制、视频画面嵌入
 * 以及异步的元数据解析。它在内部处理所有vlc事件，并缓存解析结果，
 * 对外提供简单的主动查询接口。
 */
class xdgVLC : public QObject
{
    Q_OBJECT
public:
    /**
     * @brief 构造函数
     * @param parent 父对象指针
     */
    explicit xdgVLC(QObject *parent = nullptr);

    /**
     * @brief 析构函数，负责释放所有libvlc资源
     */
    ~xdgVLC();


public:
    /**
     * @brief 设置要播放的媒体文件或URL。这是一个异步操作的起点。
     * 函数会立即返回，并在后台开始解析媒体信息。解析完成后，信息会缓存在内部。
     * @param mediaPathOrUrl 本地文件路径 或 网络媒体URL
     * @return true 如果媒体对象和播放器初步创建成功，则返回true。
     */
    bool setMedia(const QString &mediaPathOrUrl);

    /**
     * @brief 设置视频输出的窗口控件（“银幕”）
     * @param videoWidget 用于显示视频的 QWidget 指针
     */
    void setVideoWidget(QWidget *videoWidget);

    // --- 播放控制 ---
    /**
     * @brief 开始或恢复播放
     */
    void play();
    /**
     * @brief 暂停播放。再次调用play()可以恢复。
     */
    void pause();
    /**
     * @brief 异步停止播放。
     */
    void stopAsync();

    /**
     * @brief 跳转到指定的播放位置（百分比）
     * @param position 播放位置，范围从 0.0 (开始) 到 1.0 (结束)
     */
    void setPosition(float position);

    /**
     * @brief 快退指定的毫秒数
     * @param milliseconds 要快退的毫秒数 (默认 5 秒)
     */
    void rewind(int milliseconds = 5000);

    /**
     * @brief 快进指定的毫秒数
     * @param milliseconds 要快进的毫秒数 (默认 5 秒)
     */
    void forward(int milliseconds = 5000);

    /**
     * @brief 设置音量
     * @param volume 音量值，范围 0-100 (正常)。
     */
    void setVolume(int volume);

    /**
     * @brief 设置播放速率（倍速）
     * @param rate 播放速率，1.0为正常速度，0.5为半速，2.0为倍速
     */
    void setRate(float rate);

    /**
     * @brief 强制VLC使用特定的宽高比字符串。
     * * @details 这用于强制视频内容拉伸以填充窗口，忽略原始宽高比。
     * @param ratio 宽高比字符串，格式为 "宽:高" (例如 "16:9" 或 "1920:1080")。
     */
    void setAspectRatio(const QString& ratio);




    // --- 主动查询接口 ---
    /**
     * @brief 检查媒体信息是否已成功解析并可用。
     * @return true 如果信息可用，否则返回 false
     */
    bool isMediaInfoAvailable() const;

    /**
     * @brief 获取已解析的媒体信息。
     * @return 包含媒体信息的 MediaInfo 结构体。
     * @note 在调用此函数前，应先使用 isMediaInfoAvailable() 检查信息是否有效。
     */
    MediaInfo getMediaInfo() const;

    /**
     * @brief 获取当前音量
     * @return 当前音量值
     */
    int getVolume() const;

    /**
     * @brief 获取当前播放器的状态
     * @return PlayerState 枚举值，描述播放器当前所处的状态。
     */
    PlayerState getState() const;


signals:
    /**
     * @brief 当VLC内部发生严重错误时发射此信号
     * @param message 错误信息
     */
    void errorOccurred(const QString &message);

    /**
     * @brief 视频信息解析完成后发射
     */
    void mediaInfoReady();

    /**
     * @brief 当播放器成功开始播放时发射
     */
    void playing();

    /**
     * @brief 当播放器被暂停时发射
     */
    void paused();

    /**
     * @brief 当播放器被用户停止时发射
     */
    void stopped();

    /**
     * @brief 当媒体播放到结尾时发射
     */
    void ended();

    /**
     * @brief 播放时间变化时发射
     * @param time 当前播放时间 (单位：毫秒)
     */
    void timeChanged(qint64 time);

    /**
     * @brief 播放进度百分比变化时发射
     * @param position 播放位置，范围 0.0 到 1.0
     */
    void positionChanged(float position);


private:
    /**
     * @brief 初始化 libvlc 实例。这是所有操作的基础。
     * @return true 如果初始化成功，否则返回 false
     */
    bool vlcInit();

    /**
     * @brief 从当前媒体中获取指定的元数据。这是一个辅助函数，用于简化代码。
     * @param metaType 要获取的元数据类型 (来自 libvlc_meta_t 枚举)
     * @return 成功则返回元数据字符串，失败则返回空 QString
     */
    QString getMeta(libvlc_meta_t metaType);

    /**
     * @brief 这是一个由事件系统在后台调用的成员函数，
     * 负责填充 MediaInfo 结构体并更新内部状态。
     */
    void processMediaMetaChanged();

    /**
     * @brief C-style 静态回调函数，作为 libvlc 事件系统的入口。
     * 它的唯一作用是作为一个桥梁，将事件分发给对应的类实例成员函数处理。
     * @param p_event libvlc 事件指针
     * @param p_user_data 用户自定义数据 (在这里，我们传入 this 指针)
     */
    static void handleVlcEvent(const libvlc_event_t *p_event, void *p_user_data);


    // 清理绑的事件与m_libvlc_media_player与m_libvlc_media
    void cleanupPlayer();


private:
    // -------------------------------------- 核心三剑客，VLC核心对象指针 --------------------------------------
    libvlc_instance_t *m_libvlc_instance; // VLC 实例，引擎总管家。
    // 电影院的总经理：这是所有工作的起点。他负责管理整个电影院的资源，
    // 比如加载解码器（相当于电影放映技术）、管理员工和设备。没有他，电影院就无法开张。

    libvlc_media_t *m_libvlc_media; // 当前媒体对象，指向媒体资源的节目单。
    // 一张电影票：这张票上写着要放映哪部电影（比如 "D:\avatar.mkv"）。它本身不是电影，只是一个指向具体电影资源的凭证。

    libvlc_media_player_t *m_libvlc_media_player; // 当前媒体播放器对象，负责播放的演员。
    // 一台放映机：这是真正干活的设备。你把电影票 (media) 给它，它就会利用总经理 (instance) 提供的资源，
    // 把电影播放出来。所有操作（播放、暂停、快进）都是在这台放映机上完成的。

    // 所以，整个流程就是：总经理 (instance) 开张营业 -> 观众递上电影票 (media) -> 放映机 (player) 开始播放。

    // -------------------------------------- 状态和数据缓存 --------------------------------------
    MediaInfo m_mediaInfo;             // 用于缓存当前媒体的信息
    bool      m_isMediaInfoAvailable;  // 标志 m_mediaInfo 中的数据是否有效
};

#endif // __XDGVLC_H__
